#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>

#include<fcntl.h>
#include<signal.h>
#include<unistd.h>

#include "../heads/mklib_shell.h"
#include "../heads/traitements.h"

int main(int argc, char *argv[])
{
	// Vérification d'un appel correct du programme
	if(argc != 2)
	{ usage(argv[0], 1, NULL); return 1; }

	
	pid_child = -1;
	if(signal(SIGINT, redirectionSignaux) == SIG_ERR) 
	{ perror("signal SIGINT"); return 1; }
	if(signal(SIGTERM, redirectionSignaux) == SIG_ERR)
	{ perror("signal SIGTERM"); return 1; }

	// Vérification de l'existance du Makefile
	FILE * file = fopen("Makefile", "r");
	if(file == NULL) { usage(argv[0], 3, NULL); return 1; }
	printf("Fichier ouvert\n");	

	makefile_t * tmp = makefile_parse(file);
	if(tmp == NULL) { printf("Erreur makefile parse\n"); fclose(file); return 2; }
	// Le fichier est complêtement chargé, donc on le ferme
	fclose(file);

	// le makefile à été ouvert
	#ifdef _DEBUG
	// Affichage des variables
	if(tmp->vars != NULL) 
		for(int i = 0; tmp->vars[i] != NULL; i++)
			printf("var : %s\n", tmp->vars[i]->name);
	// Affichage des règles existantes
	if(tmp->rules != NULL) 
		for(int i = 0; tmp->rules[i] != NULL; i++)
			printf("rule : %s\n", tmp->rules[i]->target);
	#endif
	
	mk_rule_t *regle = trouveRegle(tmp, argv[1]);
	
	if(regle == NULL)  
	{ usage(argv[0], 2, argv[1]); makefile_free(tmp); return 2; }
	
	// Vérification  d'abscence de cycle dans la dépendance des règles
	if(verrificationCycle(tmp, regle, argv[0]) != 0) 
	{ printf("Erreur makefile analyse\n"); makefile_free(tmp); return 3; }


	if(traitementRegle(tmp, regle) != 0)
		printf("Erreur de traitement\n");

	makefile_free(tmp);
	return 0;
}

/*
// Affiche l'usage du programme en fonction du code de l'erreur :
// 	1 : Pas de cible spécifiée lors de l'appel
// 	2 : La cible spécifiée n'existe pas dans le makefile
// 	3 : Abscence de Makefile dans le répertoire de travail
// 	4 : Erreur dans le traitement de la regle passée en parramètre
// 	5 : Il y a un cycle de dépendance à partir de la dépendance cible
*/
void usage(char *name, int codeErreur, char *cible)
{
	switch(codeErreur)
	{
		case 1 : // Pas de cible 
			fprintf(stderr, "%s: *** Pas de cibles. Arrêt.\n", name);
			break;
		case 2 : // La cible est incorrecte
			fprintf(stderr, "%s: *** Pas de règle pour fabriquer la cible « %s ». Arrêt.\n", name, cible);
			break;
		case 3 : // Abscence de Makefile dans le répertoire
			fprintf(stderr, "%s: *** Aucun makefile n'a été trouvé. Arrêt.\n", name);
			break;
		case 4 : // Erreur du traitement de la regle
			fprintf(stderr, "%s: *** [%s] Erreur 1\n", name, cible);
			break;
		case 5 :
			fprintf(stderr, "%s: Dépendance circulaire %s abandonnée\n", name, cible);
			break;
	}
}

int verrificationCycle(makefile_t *makefile, mk_rule_t *regle, char *progName)
{
	for(int i = 0; regle->prereqs[i] != NULL; i++)
	{
		// On récupère la règle de la dépendance
		mk_rule_t *dependence = trouveRegle(makefile, regle->prereqs[i]);
		if(dependence == NULL) continue;
		
		
		if(strcmp(regle->target, dependence->target) == 0)
		{ usage(progName, 5, dependence->target); return -1; }

		for(int j = 0; dependence->prereqs[j] != NULL; j++)
			if(strcmp(regle->target, dependence->prereqs[j]) == 0)
			{ usage(progName, 5, dependence->prereqs[j]); return -1; }
	}
	return 0;
}


void redirectionSignaux(int sigint)
{
	#ifdef _DEBUG
	printf("Kill du processus %d\n", pid_child);
	#endif
	if(pid_child != -1)
		kill(pid_child, sigint);
	else
		kill(getpid(), sigint);
}

void reapplicationDescripteurs(int in, int out, int err)
{
	dup2(in, STDIN_FILENO);
	dup2(out, STDOUT_FILENO);
	dup2(err, STDERR_FILENO);
}

mk_rule_t *trouveRegle(makefile_t *makefile, char *regle)
{
	for(int i = 0; makefile->rules[i] != NULL; i++)
		if(strcmp(regle, makefile->rules[i]->target) == 0)
			return makefile->rules[i];
	return NULL;
}

